-- Tactician_Main.lua
-- Holds all the core functions for loading, managing the running of modules and raid encounters

-- Initialisation function
function Tactician_Loaded()
	
	if (not Tactician_SavedModuleData) then
		Tactician_SavedModuleData = { };
	end
	
	DEFAULT_CHAT_FRAME:AddMessage("Tactician: Loaded");
	
end

Tactician_Modules = { };			-- This table holds each modules information.
Tactician_LoadedModule = nil;		-- The ID of the module currently loaded.
Tactician_ModuleData = { };			-- Holds all the data and functions needed by the currently loaded module
Tactician_ModuleEvents = { };		-- Stores the events needed by the module

Tactician_RaidEncounters = { };

--[[
module is a table with the following fields.
id: The ID of the module. Must be unique.
label: The label for the module.
zone: The zone in which the encounter takes place.
encounter: Which encounter is this module associated with. Used to decide which mobs to use for loading the module.
loadFunc: Function to call when this module is loaded.
unloadFunc: (Optional) Function to call when this module is unloaded.
engageFunc: (Optional) Function to call when the raid engages the encounter.
disengageFunc: (Optional) Function to call when the raid disengages from the encounter.
defeatFunc: (Optional) Function to call when the raid defeats the encounter.
]]--
function Tactician_RegisterModule(module)

	-- !! TODO: PERFORM VALIDATION CHECKS
	if (type(module) == "table") then
		Tactician_Modules[module.id] = module;
	end
		
end

-- Calls the load function of the module with the specified id.
function Tactician_LoadModule(id)

	if (Tactician_Modules[id]) then
		if (Tactician_LoadedModule ~= nil) then
			-- There's a loaded module already. Unload it.
			Tactician_UnloadModule();
		end
		Tactician_Modules[id].loadFunc();			-- Call the load function
		Tactician_LoadedModule = id;
		DEFAULT_CHAT_FRAME:AddMessage("Tactician: " .. Tactician_Modules[id].label .. " loaded.");
		Tactician_TargetChange();
	end

end

-- Calls the unload function and clears the ModuleData table and the events
function Tactician_UnloadModule()

	local id = Tactician_LoadedModule;

	if (Tactician_Modules[id].unloadFunc) then
		Tactician_Modules[id].unloadFunc();				-- Call the unload function if there is one.
	end
	if (not Tactician_SavedModuleData[id]) then
		-- Save data doesn't exist for this module. Create it.
		Tactician_SavedModuleData[id] = { };
	end
	for k,v in pairs(Tactician_ModuleData) do
		if (v.save == 1) then
			-- Data to save.
			Tactician_SavedModuleData[id][v.id] = v;
		end
	end
	Tactician_ModuleData = { };
	Tactician_ModuleEvents = { };
	Tactician_EventFrame:UnregisterAllEvents();
	DEFAULT_CHAT_FRAME:AddMessage("Tactician: Unloading " .. Tactician_Modules[Tactician_LoadedModule].label .. ".");
	Tactician_LoadedModule = nil;

end

-- Registers a new event with the event frame
function Tactician_RegisterModuleEvent(event,func)

	if (not event) or (not func) then
		return;
	end

	Tactician_ModuleEvents[event] = func;			-- Add to the table
	Tactician_EventFrame:RegisterEvent(event);		-- Register with the frame

end

-- Handles a module event
function Tactician_HandleModuleEvent(event)
	
	Tactician_ModuleEvents[event]();

end

--[[ Add a data item to the module data table
data is a table with the following fields:
id: The ID for the data. Must be unique.
label: A short descriptor for the data.
desc: (Optional) A detailed description of the data.
type: Can be "Text", "Integer", "Boolean", "PlayerList", "List"
minValue: (For Integer/Number) Minimum value allowed.
maxValue: (For Integer/Number) Maximum value allowed
value: The current value (list of values for List)
filter: (For List) List of values allowed for selection by a list.
save: If set to 1, Tactician will take care to save this data for the module
]]--
function Tactician_AddModuleData(data)

	-- !! VALIDE THE DATA
	
	Tactician_ModuleData[data.id] = data;

end

-- Returns the value of the specified data
function Tactician_GetModuleData(id)

	if (Tactician_ModuleData[id]) then
		return Tactician_ModuleData[id].value;
	end

end

-- Add a new raid encounter
--[[
zone is the RealZoneName of the zone this encounter is found in
id is the name by which modules will refer to this encounter
units is a table with strings equivalent to monster names that are part of this encounter. Empty table for no initial units (eg. "The Lurker Below" is spawned when combat starts)
]]--
function Tactician_AddRaidEncounter(zone,id,units)

	if (not Tactician_RaidEncounters[zone]) then
		Tactician_RaidEncounters[zone] = { };
	end
	
	Tactician_RaidEncounters[zone][id] = units;

end

-- Handler for a target change
function Tactician_TargetChange()

	Tactician_LoadModuleButton:Hide();

	if (not UnitExists("target")) then
		return;
	end

	local zone = GetRealZoneText();
	
	if (not Tactician_RaidEncounters[zone]) then
		return;
	end
	
	local k,v,i;
	local unit = UnitName("target");
	
	for k,v in pairs(Tactician_RaidEncounters[zone]) do
		for i = 1, #v do
			if v[i] == unit then
				-- Raid Encounter detected!
				Tactician_RaidEncounterDetected(zone,k);
				return;
			end
		end
	end

end

-- Called when the targetted unit can be "used" to load a module
-- zone: The raid zone.
-- id: The encounter id.
function Tactician_RaidEncounterDetected(zone,id)

	DEFAULT_CHAT_FRAME:AddMessage("Raid Encounter Detected: ".. id);
	local modules = { };			-- Modules keys which can be loaded for this encounter	
	
	-- Search for modules
	for k,v in pairs(Tactician_Modules) do
		if ((v.zone == zone) and (v.encounter == id)) then
			-- Make sure this module isn't already loaded.
			if (Tactician_LoadedModule ~= k) then
				-- Correct module found. Add it's key to the list.
				tinsert(modules,k);
			end
		end
	end
	
	local i;
	if (#modules > 0) then
		local s = "Available Modules:";
		
		for i = 1, #modules do
			s = s .. " " .. modules[i];
		end
		
		DEFAULT_CHAT_FRAME:AddMessage(s);
		
		Tactician_LoadModuleButton.modules = modules;
		Tactician_LoadModuleButton:Show();
		-- !! Add functionality for right-clicking the target portrait to load a module here
	end

end

function Tactician_TEMP_TargetHandler()

	if (UnitName("target") == "Large Crag Boar") then
		Tactician_AddObjective({
			id="CRAGBOAR",
			label="Target an Elder Crag Boar",
			priority=1,
			desc=Tactician_GetModuleData("TEXTDATA"),
			time=-1,
			unique=1
		});
	elseif (UnitName("target") == "Elder Crag Boar") then
		Tactician_CompleteObjective("CRAGBOAR");
	end
	
end

function Tactician_TEMP_Load()

	DEFAULT_CHAT_FRAME:AddMessage("Hi. This is the loadFunc of the module loaded!");
	
	-- Register an event
	Tactician_RegisterModuleEvent("PLAYER_TARGET_CHANGED",Tactician_TEMP_TargetHandler);
	
	Tactician_AddModuleData({
		id = "TESTDATA",
		label = "Test Data",
		desc = "This is data for testing. Use the slider.",
		type = "integer",
		value = 5,
		maxValue = 10,
		minValue = 0
	});
	
	Tactician_AddModuleData({
		id = "TEXTDATA",
		label = "Test Data",
		desc = "This is data for testing. Use the edit box.",
		type = "text",
		value = "Hi there"
	});
	
	Tactician_AddModuleData({
		id = "PLAYERDATA",
		label = "Test Players",
		desc = "Testing the players. Use the button.",
		type = "playerlist",
		value = { },
		filter = function(unit)
					if (UnitLevel(unit) > 10) then
						return true;
					else
						return false;
					end
				end
	});
	
	Tactician_AddObjective({
		id="TIMETEST",
		label="Survive",
		priority=2,
		desc="Survive for 10 seconds.",
		time=10
	});
	
	Tactician_ModuleEditorFrame:Show();

end

Tactician_AddRaidEncounter("Orgrimmar","TEMP Encounter",{"Klishu","Horde Warbringer"});

Tactician_RegisterModule({
	id = "TEMP",
	label = "Template",
	zone = "Orgrimmar",
	encounter = "TEMP Encounter",
	loadFunc = Tactician_TEMP_Load,
	engageFunc = Tactician_TEMP_Engage,
	defeatFunc = Tactician_TEMP_Defeat
})